package org.example.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * @author: sql
 * @date: 2024/6/7
 * @Description: 主要核心工具类
 * @version: 1.0
 */
@Slf4j
public class Func {

    private Func() {
    }

    /**
     * * 判断object是否为空,集合会校验size
     */
    public static boolean isNull(Object... objs) {
        for (Object obj : objs) {
            if (isEmpty(obj)) {
                return true;
            }
        }
        return false;
    }

    /**
     * * 判断object是否不为空,集合会校验size
     */
    public static boolean isNotNull(Object... obj) {
        return !isNull(obj);
    }

    /**
     * * 判断不为空
     */
    public static boolean isEmpty(@Nullable Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length() == 0;
        }
        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }
        if (obj instanceof Iterable) {
            return !((Iterable<?>) obj).iterator().hasNext();
        }
        if (obj instanceof Iterator) {
            return !((Iterator<?>) obj).hasNext();
        }
        //else
        return false;
    }

    /**
     * * 判断为空
     */
    public static boolean isNotEmpty(@Nullable Object obj) {
        return !isEmpty(obj);
    }

    /**
     * Returns an empty list (immutable).  This list is serializable.
     *
     * @return an empty immutable list
     */
    public static <T> List<T> finalEmptyList() {
        return Collections.emptyList();
    }

    /**
     * Returns an empty set (immutable). This set is serializable.
     * Unlike the like-named field, this method is parameterized.
     *
     * @return an empty immutable set
     */
    public static <T> Set<T> finalEmptySet() {
        return Collections.emptySet();
    }

    /**
     * Returns an empty sorted map (immutable). This map is serializable.
     *
     * @return an empty immutable map
     */
    public static <K, V> Map<K, V> finalEmptyMap() {
        return Collections.emptyMap();
    }


    public static String emptyString() {
        return "";
    }

    public static <T> List<T> emptyList() {
        return new ArrayList<>();
    }

    public static <T> Set<T> emptySet() {
        return new HashSet<>();
    }

    public static <K, V> Map<K, V> emptyMap() {
        return new HashMap<>();
    }

    /**
     * 取出集合中第一个元素
     *
     * @param coll 集合实例
     * @param <E>  集合中元素类型
     * @return 泛型类型
     */
    public static <E> E toObj(Collection<E> coll) {
        if (isNotEmpty(coll)) {
            return coll.iterator().next();
        }
        return null;
    }

    /**
     * 将对象集合按照一定规则映射后收集为另一种形式的集合
     *
     * @param <R>       最终结果的泛型
     * @param <S>       原始集合元素的类泛型
     * @param <T>       转换后元素的中间状态泛型
     * @param <A>       最终结果收集器泛型
     * @param source    最原始的集合实例
     * @param mapper    转换规则
     * @param collector 收集器的类型
     * @return 变换后存储新元素的集合实例
     */
    public static <R, S, T, A> R collect(final Collection<S> source, Function<? super S, ? extends T> mapper, Collector<? super T, A, R> collector) {
        if (source == null) {
            return null;
        }
        Objects.requireNonNull(mapper);
        Objects.requireNonNull(collector);
        return source.stream().map(mapper).filter(Objects::nonNull).collect(collector);
    }

    public static <T, R> R toObj(final T obj, final Function<? super T, ? extends R> mapper) {
        Objects.requireNonNull(mapper);
        return Optional.ofNullable(obj).map(mapper).orElse(null);
    }

    public static <T, R> List<R> toList(final Collection<T> list, final Function<? super T, ? extends R> mapper) {
        return collect(list, mapper, Collectors.toList());
    }

    public static <T> List<T> toList(final T[] arrays) {
        if (arrays == null) {
            return emptyList();
        }
        return new ArrayList<>(Arrays.asList(arrays));
    }

    public static <T, R> List<R> toList(final T[] arrays, final Function<? super T, ? extends R> mapper) {
        return toList(toList(arrays), mapper);
    }

    public static <T, R> List<R> toList(final Collection<T> list, final Function<? super T, ? extends R> mapper, Predicate<R> predicate) {
        Objects.requireNonNull(mapper);
        Objects.requireNonNull(predicate);
        if (Objects.nonNull(list)) {
            return list.stream().map(mapper).filter(predicate).collect(Collectors.toList());
        }
        return emptyList();
    }

    /**
     * 将集合转化成Map
     *
     * @param list      集合实例
     * @param keyAction key转换规则
     * @param <T>       集合实体类泛型
     * @param <K>       Key实体类型泛型
     * @return Map实例
     * @since 1.6.0
     */
    public static <T, K> Map<K, T> toMap(final Collection<T> list, Function<? super T, ? extends K> keyAction) {
        Objects.requireNonNull(keyAction);
        return toMap(list, keyAction, Function.identity());
    }


    /**
     * 将集合转化成Map
     *
     * @param list        集合实例
     * @param keyAction   key转换规则
     * @param valueAction value转换规则
     * @param <T>         集合实体类泛型
     * @param <K>         Key实体类型泛型
     * @param <V>         Value实体类型泛型
     * @return Map实例
     */
    public static <T, K, V> Map<K, V> toMap(final Collection<T> list, Function<? super T, ? extends K> keyAction, Function<? super T, ? extends V> valueAction) {
        Objects.requireNonNull(keyAction);
        Objects.requireNonNull(valueAction);
        if (isNotEmpty(list)) {
            return list.stream().collect(Collectors.toMap(keyAction, valueAction));
        }
        return Collections.emptyMap();
    }


    /**
     * 将List集合以一种类型转换成Set集合
     *
     * @param <T>  源数据类型
     * @param list 源List集合
     * @return 变换后的类型集合，如果source为null,则返回空集合
     */
    public static <T> Set<T> toSet(final Collection<T> list) {
        if (isNotEmpty(list)) {
            //这里不使用流 使用构造器性能更好
            return new HashSet<>(list);
        }
        return Collections.emptySet();
    }

    /**
     * 将List集合以一种类型转换成Set集合
     *
     * @param <T>    源数据类型
     * @param <R>    变换后数据类型
     * @param data   源List集合
     * @param mapper 映射Lambda表达式
     * @return 变换后的类型集合，如果source为null,则返回空集合
     */
    public static <T, R> Set<R> toSet(final Collection<T> data, final Function<? super T, ? extends R> mapper) {
        Objects.requireNonNull(mapper);
        if (Objects.nonNull(data)) {
            return data.stream().map(mapper).collect(Collectors.toSet());
        }
        return Collections.emptySet();
    }

    /**
     * BigDecimal 求和
     *
     * @param list
     * @param mapper
     * @return
     */
    public static <T> BigDecimal sumNumber(final Collection<T> list, final Function<? super T, BigDecimal> mapper) {
        // 使用Stream API来求和amount字段
        return list.stream()
                .map(mapper) // 将每个对象映射到它的amount字段
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 整数叠减
     *
     * @param nums
     * @return
     */
    public static int subInt(Integer... nums) {
        int result = 0;
        if (nums.length > 0) {
            result = nums[0];
            for (int i = 1; i < nums.length; i++) {
                if (nums[i] == null) {
                    continue;
                }
                result -= nums[i];
            }
        }
        return result;
    }

    /**
     * BigDecimal 叠减
     *
     * @param nums
     * @return
     */
    public static BigDecimal subBigDecimal(BigDecimal... nums) {
        BigDecimal result = BigDecimal.ZERO;
        if (nums.length > 0) {
            if (nums[0] != null) {
                result = nums[0];
            }
            for (int i = 1; i < nums.length; i++) {
                if (nums[i] == null) {
                    continue;
                }
                result = result.subtract(nums[i]);
            }
        }
        return result;
    }

    /**
     * <p>对集合中元素按照指定列进行分组</p>
     * <p>返回值是{@code Map}，其中Key为分组列，Value为当前元素</p>
     *
     * @param list    集合实例
     * @param gColumn 分组列（方法引用表示）
     * @param <E>     集合元素泛型
     * @param <G>     分组列数据类型泛型
     * @return {@code Map}实例
     * @since 1.6.0
     */
    public static <E, G> Map<G, List<E>> groupBy(final Collection<E> list, final Function<E, G> gColumn) {
        Objects.requireNonNull(gColumn);
        if (Objects.nonNull(list)) {
            return list.stream().collect(Collectors.groupingBy(gColumn));
        }
        return Collections.emptyMap();
    }

    /**
     * <p>对集合中元素按照指定列进行分组</p>
     * <p>返回值是{@code Map}，其中Key为分组列，Value为当前元素</p>
     * <p>通过比较器对集合中元素排序</p>
     *
     * @param list    集合实例
     * @param gColumn 分组列（方法引用表示）
     * @param <E>     集合元素泛型
     * @param <G>     分组列数据类型泛型
     * @return {@code Map}实例
     * @since 1.6.1
     */
    public static <E, G> Map<G, List<E>> groupBy(final Collection<E> list, final Function<E, G> gColumn, Comparator<E> comparator) {
        Objects.requireNonNull(comparator);
        Map<G, List<E>> map = groupBy(list, gColumn);
        map.forEach((k, v) -> v.sort(comparator));
        return map;
    }

    /**
     * <p>对集合中元素按照指定列进行分组</p>
     * <p>返回值是{@code Map}，其中Key为分组列</p>
     *
     * @param list    集合实例
     * @param gColumn 分组列（方法引用表示）
     * @param mapper  转换行为
     * @param <U>     Value集合元素类型泛型
     * @param <E>     集合元素泛型
     * @param <G>     分组列数据类型泛型
     * @return {@code Map}实例
     * @since 1.6.0
     */
    public static <E, G, U> Map<G, List<U>> groupBy(final Collection<E> list, final Function<E, G> gColumn, final Function<E, U> mapper) {
        Objects.requireNonNull(gColumn);
        if (Objects.nonNull(list)) {
            return list.stream().collect(Collectors.groupingBy(gColumn, Collectors.mapping(mapper, Collectors.toList())));
        }
        return Collections.emptyMap();
    }

    /**
     * 使用MD5算法处理字符串
     *
     * @param text 字符串
     * @return 处理后的字符串
     */
    public static String md5(String text) {
        Assert.notNull(text, "Text must not be null");
        try {
            //生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            //计算md5函数
            md.update(text.getBytes());
            //16是表示转换为16进制数
            return new BigInteger(1, md.digest()).toString(16);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return text;
    }

    public static List<String> getFieldListNames(Class<?> clazz) {
        List<String> fieldNames = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields(); // 获取所有声明的字段，不包括继承的字段
        for (Field field : fields) {
            field.setAccessible(true); // 设置为可访问
            fieldNames.add(field.getName()); // 获取字段名称
        }
        return fieldNames;
    }

    public static List<Field> getFieldList(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields(); // 获取所有声明的字段，不包括继承的字段
        // 如果你也想获取继承的字段，可以使用 clazz.getFields()

        for (Field field : fields) {
            field.setAccessible(true); // 设置为可访问
            fieldList.add(field); // 获取字段名称
        }
        return fieldList;
    }

    /**
     * 对集合按照指定长度分段，每一个段为单独的集合，返回这个集合的列表
     *
     * @param <T>        集合元素类型
     * @param collection 集合
     * @param size       每个段的长度
     * @return 分段列表
     */
    public static <T> List<List<T>> split(Collection<T> collection, int size) {
        final List<List<T>> result = new ArrayList<>();
        if (isEmpty(collection)) {
            return result;
        }

        ArrayList<T> subList = new ArrayList<>(size);
        for (T t : collection) {
            if (subList.size() >= size) {
                result.add(subList);
                subList = new ArrayList<>(size);
            }
            subList.add(t);
        }
        result.add(subList);
        return result;
    }

    public static <K, V> HashMap<K, V> newHashMap() {
        return new HashMap<K, V>();
    }

    /**
     * Creates a <em>mutable</em> {@link ArrayList}.
     *
     * @param <T> the generic type of the {@code ArrayList} to create.
     * @return the created {@code ArrayList}, of {@code null} if the given array of elements is {@code null}.
     */
    public static <T> ArrayList<T> newArrayList() {
        return new ArrayList<>();
    }


    /**
     * 将下划线命名转换为驼峰命名
     *
     * @param underScoreStr 下划线命名的字符串
     * @return 驼峰命名的字符串
     */
    public static String convertUnderScoreToCamelCase(String underScoreStr) {
        if (underScoreStr == null || underScoreStr.isEmpty()) {
            return "";
        }
        StringBuilder camelCaseStr = new StringBuilder();
        boolean nextUpperCase = false;
        for (char c : underScoreStr.toCharArray()) {
            if (c == '_') {
                nextUpperCase = true;
            } else {
                if (nextUpperCase) {
                    camelCaseStr.append(Character.toUpperCase(c));
                    nextUpperCase = false;
                } else {
                    camelCaseStr.append(Character.toLowerCase(c));
                }
            }
        }
        return camelCaseStr.toString();
    }


    /**
     * <p>Capitalizes a String changing the first character to title case as
     * per {@link Character#toTitleCase(char)}. No other characters are changed.</p>
     * <p>
     * A {@code null} input String returns {@code null}.</p>
     *
     * <pre>
     * StringUtils.capitalize(null)  = null
     * StringUtils.capitalize("")    = ""
     * StringUtils.capitalize("cat") = "Cat"
     * StringUtils.capitalize("cAt") = "CAt"
     * StringUtils.capitalize("'cat'") = "'cat'"
     * </pre>
     *
     * @param str the String to capitalize, may be null
     * @return the capitalized String, {@code null} if null String input
     * @since 2.0
     */
    public static String capitalize(final String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return str;
        }

        final char firstChar = str.charAt(0);
        final char newChar = Character.toTitleCase(firstChar);
        if (firstChar == newChar) {
            // already capitalized
            return str;
        }

        char[] newChars = new char[strLen];
        newChars[0] = newChar;
        str.getChars(1, strLen, newChars, 1);
        return String.valueOf(newChars);
    }

    /**
     * 解析 Url 中的数据库
     */
    public static String parseUrlDbName(String url) {
        return url.substring(url.lastIndexOf("/") + 1, url.indexOf("?"));
    }

}
